package com.immediatus.graphics.texture;

import com.immediatus.graphics.contracts.ITextureAtlas;
import com.immediatus.graphics.contracts.ITextureAtlasSource;

import java.util.ArrayList;

public abstract class TextureAtlas<T extends ITextureAtlasSource> extends Texture implements ITextureAtlas<T>{
    private final int _width;
    private final int _height;
    private final ArrayList<T> _textureAtlasSources = new ArrayList<T>();

    public TextureAtlas(final int width_, final int height_, final PixelFormat pixelFormat_, final TextureOptions textureOptions_, final ITextureAtlasStateListener<T> _textureAtlasStateListener){
        super(pixelFormat_, textureOptions_, _textureAtlasStateListener);
        this._width = width_;
        this._height = height_;
    }

    @Override
    public int getWidth(){
        return this._width;
    }

    @Override
    public int getHeight(){
        return this._height;
    }

    @Override
    public ITextureAtlasStateListener<T> getTextureStateListener(){
        return (ITextureAtlasStateListener<T>) super.getTextureStateListener();
    }

    @Override
    public void addTextureAtlasSource(final T textureAtlasSource_, final int texturePositionX_, final int texturePositionY_){
        this.checkTextureAtlasSourcePosition(textureAtlasSource_, texturePositionX_, texturePositionY_);
        textureAtlasSource_.setTexturePositionX(texturePositionX_);
        textureAtlasSource_.setTexturePositionY(texturePositionY_);
        this._textureAtlasSources.add(textureAtlasSource_);
        this._UpdateOnHardwareNeeded = true;
    }

    @Override
    public void removeTextureAtlasSource(final T textureAtlasSource_, final int texturePositionX_, final int texturePositionY_){
        final ArrayList<T> textureSources = this._textureAtlasSources;
        for (int i = textureSources.size() - 1; i >= 0; i--){
            final T textureSource = textureSources.get(i);
            if (textureSource == textureAtlasSource_ && textureSource.getTexturePositionX() == texturePositionX_ &&
                    textureSource.getTexturePositionY() == texturePositionY_){
                textureSources.remove(i);
                this._UpdateOnHardwareNeeded = true;
                return;
            }
        }
    }

    @Override
    public void clearTextureAtlasSources(){
        this._textureAtlasSources.clear();
        this._UpdateOnHardwareNeeded = true;
    }

    protected ArrayList<T> getTextureAtlasSources(){
        return _textureAtlasSources;
    }

    private void checkTextureAtlasSourcePosition(final T textureAtlasSource_, final int texturePositionX_, final int texturePositionY_) throws IllegalArgumentException{
        if (texturePositionX_ < 0){
            throw new IllegalArgumentException(
                    "Illegal negative texturePositionX supplied: '" + texturePositionX_ + "'");
        } else if (texturePositionY_ < 0){
            throw new IllegalArgumentException(
                    "Illegal negative texturePositionY supplied: '" + texturePositionY_ + "'");
        } else if (texturePositionX_ + textureAtlasSource_.getWidth() > this.getWidth() ||
                texturePositionY_ + textureAtlasSource_.getHeight() > this.getHeight()){
            throw new IllegalArgumentException("Supplied TextureAtlasSource must not exceed bounds of Texture.");
        }
    }
}
